home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Comunicatii / htttrack / httrack-3.32-2.exe / {app} / src / htsftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-08  |  33.1 KB  |  1,175 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Gestion protocole ftp
  41. // Version .05 (01/2000)
  42.  
  43. #include "htsftp.h"
  44.  
  45. #include "htsglobal.h"
  46. #include "htsbase.h"
  47. #include "htsnet.h"
  48. #include "htsthread.h"
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #include <process.h>    /* _beginthread, _endthread */
  59. #endif
  60. #endif
  61.  
  62. // ftp mode passif
  63. // #if HTS_INET6==0
  64. #define FTP_PASV 1
  65. // #else
  66. // no passive mode for v6
  67. // #define FTP_PASV 0
  68. // #endif
  69.  
  70. #define FTP_DEBUG 0
  71. //#define FORK_DEBUG 0
  72.  
  73. #define FTP_STATUS_READY 1001
  74.  
  75. #if USE_BEGINTHREAD
  76. /*
  77. #ifdef __cplusplus
  78. // C++ -> Shell
  79. UINT back_launch_ftp( LPVOID pP ) {
  80.   lien_back* back=(lien_back*) pP;
  81.   if (back == NULL) {
  82.     //back->status=FTP_STATUS_READY;    // fini
  83.     //back->r.statuscode=-1;
  84.     return -1;
  85.   }
  86.   
  87.   // lancer ftp
  88.   run_launch_ftp(back);
  89.   // prΩt
  90.   back->status=0;
  91.  
  92.   return 0;    // thread completed successfully
  93. }
  94. #else
  95. */
  96. PTHREAD_TYPE back_launch_ftp( void* pP ) {
  97.   lien_back* back=(lien_back*) pP;
  98.   if (back == NULL) {
  99.     //back->status=FTP_STATUS_READY;    // fini
  100.     //back->r.statuscode=-1;
  101. #if FTP_DEBUG
  102.     printf("[ftp error: no args]\n");
  103. #endif
  104.     return PTHREAD_RETURN;
  105.   }
  106.  
  107.   /* Initialize */ 
  108.   hts_init();
  109.  
  110.   // lancer ftp
  111. #if FTP_DEBUG
  112.   printf("[Launching main ftp routine]\n");
  113. #endif
  114.   run_launch_ftp(back);
  115.   // prΩt
  116.   back->status=0;
  117.   
  118.   /* Uninitialize */
  119.   hts_uninit();
  120.   return PTHREAD_RETURN;
  121. }
  122. /*#endif*/
  123. // lancer en back
  124. void launch_ftp(lien_back* back) {
  125. /*
  126. #ifdef __cplusplus
  127.   // C++ -> Shell
  128.   AfxBeginThread(back_launch_ftp,(LPVOID) back);
  129. #else
  130. */
  131.   // DOS
  132. #if FTP_DEBUG
  133.   printf("[Launching main ftp thread]\n");
  134. #endif
  135.   _beginthread(back_launch_ftp, 0, (void*) back);
  136. /*#endif*/
  137. }
  138.  
  139. #else
  140. // Unix sans pthread
  141. int back_launch_ftp(lien_back* back) {
  142.   // lancer ftp
  143.   run_launch_ftp(back);
  144.   // prΩt
  145.   back->status=0;
  146.   return 0;
  147. }
  148. void launch_ftp(lien_back* back,char* path,char* exec) {
  149.   FILE* fp = fopen(fconv(path),"wb");
  150.   if (fp) {
  151.     char _args[8][256];
  152.     char *args[8];
  153.     fclose(fp); fp=NULL;
  154.     
  155.     strcpybuff(_args[0],exec);
  156.     strcpybuff(_args[1],"-#R");
  157.     strcpybuff(_args[2],back->url_adr);
  158.     strcpybuff(_args[3],back->url_fil);
  159.     strcpybuff(_args[4],back->url_sav);
  160.     strcpybuff(_args[5],path);
  161.     //strcpybuff(_args[6],"");
  162.     args[0]=_args[0];
  163.     args[1]=_args[1];
  164.     args[2]=_args[2];
  165.     args[3]=_args[3];
  166.     args[4]=_args[4];
  167.     args[5]=_args[5];
  168.     args[6]=NULL;
  169.     switch (fork()) {    // note: vfork dΘconne un max'
  170.     case -1: printf("Can not vfork() process\n"); break;
  171.     case 0: 
  172.       if (execvp(args[0],args)==-1) {
  173.         fp=fopen(fconv(path),"wb");
  174.         if (fp) {
  175.           fprintf(fp,"-1 unable to launch %s",args[0]);
  176.           fclose(fp); fp=NULL;
  177.           rename(path,concat(path,".ok"));
  178.         } else remove(path);
  179.       }
  180.       _exit(0);    // exit 'propre'
  181.       break;
  182.     default:  // parent
  183.       // bah on fait rien..
  184.       break;         
  185.     }
  186.   }
  187. }
  188. #endif
  189.  
  190. // pour l'arrΩt du ftp
  191. #ifdef _WIN32
  192. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  193. #else
  194. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  195. #endif
  196. #define _HALT_FTP { \
  197.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  198.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  199.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  200. }
  201. #define _CHECK_HALT_FTP \
  202.   if (stop_ftp(back)) { \
  203.   _HALT_FTP \
  204.   return 0; \
  205.   }
  206.  
  207. // la vΘritable fonction une fois lancΘes les routines thread/fork
  208. int run_launch_ftp(lien_back* back) {
  209.   char user[256]="anonymous";
  210.   char pass[256]="user@";
  211.   char line_retr[2048];
  212.   int port=21;
  213. #if FTP_PASV
  214.   int port_pasv=0;
  215. #endif
  216.   char adr_ip[1024];
  217.   char *adr,*real_adr;
  218.   char* ftp_filename="";
  219.   int timeout = 300;    // timeout
  220.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  221.   int transfer_list=0;  // directory
  222.   int rest_understood=0;  // rest command understood
  223.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  224.   //
  225.   T_SOC soc_ctl=INVALID_SOCKET;
  226.   T_SOC soc_servdat=INVALID_SOCKET;
  227.   T_SOC soc_dat=INVALID_SOCKET;
  228.   //
  229.   SOCaddr server_data;
  230.   int server_data_size=sizeof(server_data);
  231.   //
  232.   line_retr[0]=adr_ip[0]='\0';
  233.   
  234.   timeout=300;
  235.   
  236.   // effacer
  237.   strcpybuff(back->r.msg,"");
  238.   back->r.statuscode=0;
  239.   back->r.size=0;
  240.   
  241.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  242.   real_adr = strchr(back->url_adr,':');
  243.   if (real_adr) real_adr++;
  244.   else real_adr=back->url_adr;
  245.   while(*real_adr=='/') real_adr++;    // sauter /
  246.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  247.     int i=-1;
  248.     pass[0]='\0';
  249.     do {
  250.       i++;
  251.       user[i]=real_adr[i];
  252.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  253.     user[i]='\0';
  254.     if (real_adr[i]==':') {    // pass
  255.       int j=-1;
  256.       i++;  // oui on saute aussi le :
  257.       do {
  258.         j++;
  259.         pass[j]=real_adr[i+j];
  260.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  261.       pass[j]='\0';
  262.     }
  263.   }
  264.   
  265.   // Calculer RETR <nom>
  266.   {
  267.     char* a;
  268. #if 0
  269.     a=back->url_fil + strlen(back->url_fil)-1;
  270.     while( (a > back->url_fil) && (*a!='/')) a--;
  271.     if (*a != '/') {
  272.       a = NULL;
  273.     }
  274. #else
  275.     a = back->url_fil;
  276. #endif
  277.     if (a != NULL && *a != '\0') {
  278. #if 0
  279.       a++;    // sauter /
  280. #endif
  281.       ftp_filename=a;
  282.       if (strnotempty(a)) {
  283.         char* ua=unescape_http(a);
  284.         if (
  285.           (strchr(ua, ' '))
  286.           ||
  287.           (strchr(ua, '\"'))
  288.           ||
  289.           (strchr(ua, '\''))
  290.           ) {
  291.           sprintf(line_retr,"RETR \"%s\"",ua);
  292.         } else {      /* Regular one */
  293.           sprintf(line_retr,"RETR %s",ua);
  294.         }
  295.       } else {
  296.         transfer_list=1;
  297.         sprintf(line_retr,"LIST -A");
  298.       }
  299.     } else {
  300.       strcpybuff(back->r.msg,"Unexpected PORT error");
  301.       back->status=FTP_STATUS_READY;    // fini
  302.       back->r.statuscode=-1;
  303.     }
  304.   }
  305.   
  306. #if FTP_DEBUG
  307.   printf("Connecting to %s...\n",adr);
  308. #endif
  309.   
  310.   // connexion
  311.   {
  312.     SOCaddr server;
  313.     int server_size=sizeof(server);
  314.     t_hostent* hp;    
  315.     char * a;
  316.     char _adr[256];
  317.     _adr[0]='\0';
  318.     //T_SOC soc_ctl;
  319.     // effacer structure
  320.     memset(&server, 0, sizeof(server));
  321.     
  322.     // port
  323.     a=strchr(adr,':');    // port
  324.     if (a) {
  325.       sscanf(a+1,"%d",&port);
  326.       strncatbuff(_adr,adr,(int) (a - adr));
  327.     } else
  328.       strcpybuff(_adr,adr);
  329.     
  330.     // rΘcupΘrer adresse rΘsolue
  331.     strcpybuff(back->info,"host name");
  332.     hp = hts_gethostbyname(_adr, &fullhostent_buffer);
  333.     if (hp == NULL) {
  334.       strcpybuff(back->r.msg,"Unable to get server's address");
  335.       back->status=FTP_STATUS_READY;    // fini
  336.       back->r.statuscode=-5;
  337.       _HALT_FTP
  338.         return 0;
  339.     }
  340.     _CHECK_HALT_FTP;
  341.     
  342.     // copie adresse
  343.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  344.     // copie adresse pour cnx data
  345.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  346.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  347.     
  348.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  349.     soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  350.     if (soc_ctl==INVALID_SOCKET) {
  351.       strcpybuff(back->r.msg,"Unable to create a socket");
  352.       back->status=FTP_STATUS_READY;    // fini
  353.       back->r.statuscode=-1;
  354.       _HALT_FTP
  355.         return 0;
  356.     }
  357.  
  358.     SOCaddr_initport(server, port);
  359.     // server.sin_port = htons((unsigned short int) port);
  360.     
  361.     // connexion (bloquante, on est en thread)
  362.     strcpybuff(back->info,"connect");
  363.  
  364. #if HTS_WIN
  365.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  366. #else
  367.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  368. #endif
  369.         strcpybuff(back->r.msg,"Unable to connect to the server");
  370.         back->status=FTP_STATUS_READY;    // fini
  371.         back->r.statuscode=-1;
  372.         _HALT_FTP
  373.           return 0;
  374. #if HTS_WIN
  375.       }
  376. #else
  377.     }
  378. #endif
  379.     _CHECK_HALT_FTP;
  380.     
  381.     {
  382.       char line[1024];
  383.       // envoi du login
  384.       
  385.       // --USER--
  386.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  387.       _CHECK_HALT_FTP;
  388.       
  389.       if (line[0]=='2') {        // ok, connectΘ
  390.         strcpybuff(back->info,"login: user");
  391.         sprintf(line,"USER %s",user);
  392.         send_line(soc_ctl,line);
  393.         get_ftp_line(soc_ctl,line,timeout);
  394.         _CHECK_HALT_FTP;      
  395.         if ((line[0]=='3') || (line[0]=='2')) {
  396.           // --PASS--
  397.           strcpybuff(back->info,"login: pass");
  398.           sprintf(line,"PASS %s",pass);
  399.           send_line(soc_ctl,line);
  400.           get_ftp_line(soc_ctl,line,timeout);
  401.           _CHECK_HALT_FTP;      
  402.           if (line[0]=='2') {  // ok
  403.             send_line(soc_ctl,"TYPE I");
  404.             get_ftp_line(soc_ctl,line,timeout);
  405.             _CHECK_HALT_FTP;      
  406.             if (line[0]=='2') {
  407.               // ok
  408.             } else {
  409.               strcpybuff(back->r.msg,"TYPE I error");
  410.               back->status=FTP_STATUS_READY;    // fini
  411.               back->r.statuscode=-1;
  412.             }
  413. #if 0
  414.             // --CWD--
  415.             char* a;
  416.             a=back->url_fil + strlen(back->url_fil)-1;
  417.             while( (a > back->url_fil) && (*a!='/')) a--;
  418.             if (*a == '/') {    // ok repΘrΘ
  419.               char target[1024];
  420.               target[0]='\0';
  421.               strncatbuff(target,back->url_fil,(int) (a - back->url_fil));
  422.               if (strnotempty(target)==0)
  423.                 strcatbuff(target,"/");
  424.               strcpybuff(back->info,"cwd");
  425.               sprintf(line,"CWD %s",target);
  426.               send_line(soc_ctl,line);
  427.               get_ftp_line(soc_ctl,line,timeout);
  428.               _CHECK_HALT_FTP;      
  429.               if (line[0]=='2') {
  430.                 send_line(soc_ctl,"TYPE I");
  431.                 get_ftp_line(soc_ctl,line,timeout);
  432.                 _CHECK_HALT_FTP;      
  433.                 if (line[0]=='2') {
  434.                   // ok..
  435.                 } else {
  436.                   strcpybuff(back->r.msg,"TYPE I error");
  437.                   back->status=FTP_STATUS_READY;    // fini
  438.                   back->r.statuscode=-1;
  439.                 }
  440.               } else {
  441.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  442.                 back->status=FTP_STATUS_READY;    // fini
  443.                 back->r.statuscode=-1;
  444.               }    // sinon on est prΩts
  445.             } else {
  446.               strcpybuff(back->r.msg,"Unexpected ftp error");
  447.               back->status=FTP_STATUS_READY;    // fini
  448.               back->r.statuscode=-1;
  449.             }
  450. #endif
  451.             
  452.           } else {
  453.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  454.             back->status=FTP_STATUS_READY;    // fini
  455.             back->r.statuscode=-1;
  456.           }
  457.         } else {
  458.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  459.           back->status=FTP_STATUS_READY;    // fini
  460.           back->r.statuscode=-1;
  461.         }
  462.       } else {
  463.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  464.         back->status=FTP_STATUS_READY;    // fini
  465.         back->r.statuscode=-1;
  466.       }
  467.      
  468.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  469.       if (back->r.statuscode != -1) {
  470.  
  471.         
  472.         //
  473.         // PrΘ-REST
  474.         //
  475. #if FTP_PASV
  476.         if (SOCaddr_getproto(server, server_size) == '1') {
  477.           strcpybuff(back->info,"pasv");
  478.           sprintf(line,"PASV");
  479.           send_line(soc_ctl,line);
  480.           get_ftp_line(soc_ctl,line,timeout);
  481.         } else { /* ipv6 */
  482.           line[0]='\0';
  483.         }
  484.         _CHECK_HALT_FTP;      
  485.         if (line[0]=='2') {
  486.           char *a,*b,*c;
  487.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  488.           if (a) {
  489.            
  490.             // -- analyse de l'adresse IP et du port --
  491.             a++;
  492.             b=strchr(a,',');
  493.             if (b) b=strchr(b+1,',');
  494.             if (b) b=strchr(b+1,',');
  495.             if (b) b=strchr(b+1,',');
  496.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  497.             if (b) *b='\0';
  498.             //
  499.             strcpybuff(adr_ip,a);       // copier adresse ip
  500.             //
  501.             if (b) {
  502.               a=b+1;  // dΘbut du port
  503.               b=strchr(a,'.');
  504.               if (b) {
  505.                 int n1,n2;
  506.                 //
  507.                 *b='\0';
  508.                 b++;
  509.                 c=strchr(b,')');
  510.                 if (c) {
  511.                   *c='\0';
  512.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  513.                     port_pasv=n2+(n1<<8);
  514.                   }
  515.                 } else {
  516.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  517.                 }    // sinon on est prΩts
  518.               }
  519.             }
  520.             // -- fin analyse de l'adresse IP et du port --
  521.           } else {
  522.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  523.             back->status=FTP_STATUS_READY;    // fini
  524.             back->r.statuscode=-1;
  525.           }    // sinon on est prΩts
  526.         } else {
  527.           /*
  528.             * try epsv (ipv6) *
  529.           */
  530.           strcpybuff(back->info,"pasv");
  531.           sprintf(line,"EPSV");
  532.           send_line(soc_ctl,line);
  533.           get_ftp_line(soc_ctl,line,timeout);
  534.           _CHECK_HALT_FTP;      
  535.           if (line[0]=='2') { /* got it */
  536.             char *a;
  537.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  538.             if (
  539.               (a != NULL)
  540.               &&
  541.               (*a == '(') 
  542.               && (*(a+1))
  543.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  544.               && (isdigit(*(a+4)))
  545.               && (*(a+5))
  546.               ) {
  547.               unsigned int n1 = 0;
  548.               if (sscanf(a+4,"%d",&n1)==1) {
  549.                 if ((n1 < 65535) && (n1 > 0)) {
  550.                   port_pasv=n1;
  551.                 }
  552.               }
  553.             } else {
  554.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  555.               back->status=FTP_STATUS_READY;    // fini
  556.               back->r.statuscode=-1;
  557.             }
  558.           } else {
  559.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  560.             back->status=FTP_STATUS_READY;    // fini
  561.             back->r.statuscode=-1;
  562.           }    // sinon on est prΩts
  563.         }
  564. #else
  565.         // rien α faire avant
  566. #endif
  567.           
  568. #if FTP_PASV
  569.         if (port_pasv) {
  570. #endif
  571.           // SIZE
  572.           if (back->r.statuscode != -1) {
  573.             if (!transfer_list) {
  574.               char* ua=unescape_http(ftp_filename);
  575.               if (
  576.                 (strchr(ua, ' '))
  577.                 ||
  578.                 (strchr(ua, '\"'))
  579.                 ||
  580.                 (strchr(ua, '\''))
  581.                 ) {
  582.                 sprintf(line,"SIZE \"%s\"", ua);
  583.               } else {
  584.                 sprintf(line,"SIZE %s", ua);
  585.               }
  586.               
  587.               // SIZE?
  588.               strcpybuff(back->info,"size");
  589.               send_line(soc_ctl,line);
  590.               get_ftp_line(soc_ctl,line,timeout);
  591.               _CHECK_HALT_FTP;      
  592.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  593.                 char* szstr = strchr(line, ' ');
  594.                 if (szstr) {
  595.                   LLint size = 0;
  596.                   szstr++;
  597.                   if (sscanf(szstr, LLintP, &size) == 1) {
  598.                     back->r.totalsize = size;
  599.                   }
  600.                 }
  601.  
  602.                 // REST?
  603.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  604.                   strcpybuff(back->info,"rest");
  605.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  606.                   send_line(soc_ctl,line);
  607.                   get_ftp_line(soc_ctl,line,timeout);
  608.                   _CHECK_HALT_FTP;      
  609.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  610.                     rest_understood=1;
  611.                   } // sinon tant pis 
  612.                 } 
  613.               }  // sinon tant pis 
  614.             }
  615.           }
  616. #if FTP_PASV
  617.         }
  618. #endif
  619.  
  620.         //
  621.         // Post-REST
  622.         //
  623. #if FTP_PASV
  624.         // Ok, se connecter
  625.         if (port_pasv) {
  626.           SOCaddr server;
  627.           int server_size=sizeof(server);
  628.           t_hostent* hp;    
  629.           // effacer structure
  630.           memset(&server, 0, sizeof(server));
  631.           
  632.           // infos
  633.           strcpybuff(back->info,"resolv");
  634.           
  635.           // rΘsoudre
  636.           if (adr_ip[0]) {
  637.             hp = hts_gethostbyname(adr_ip, &fullhostent_buffer);
  638.             if (hp) {
  639.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  640.             } else {
  641.               server_size=0;
  642.             }
  643.           } else {
  644.             memcpy(&server, &server_data, sizeof(server_data));
  645.             server_size=server_data_size;
  646.           }
  647.           
  648.           // infos
  649.           strcpybuff(back->info,"cnxdata");
  650. #if FTP_DEBUG
  651.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  652. #endif
  653.           if (server_size > 0) {
  654.             // socket
  655.             soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  656.             if (soc_dat != INVALID_SOCKET) {
  657.               // structure: connexion au domaine internet, port 80 (ou autre)
  658.               SOCaddr_initport(server, port_pasv);
  659.               // server.sin_port = htons((unsigned short int) port_pasv);
  660. #if HTS_WIN
  661.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  662. #else
  663.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  664. #endif
  665.                 strcpybuff(back->info,"retr");
  666.                 strcpybuff(line,line_retr);
  667.                 send_line(soc_ctl,line);
  668.                 get_ftp_line(soc_ctl,line,timeout);
  669.                 _CHECK_HALT_FTP;      
  670.                 if (line[0]=='1') {
  671.                   // OK
  672.                 } else {
  673.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  674.                   //
  675.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  676.                   back->status=FTP_STATUS_READY;    // fini
  677.                   back->r.statuscode=-1;
  678.                 }    // sinon on est prΩts
  679.               } else {
  680. #if FTP_DEBUG
  681.                 printf("Data: unable to connect\n");
  682. #endif
  683.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  684.                 //
  685.                 strcpybuff(back->r.msg,"Unable to connect");
  686.                 back->status=FTP_STATUS_READY;    // fini
  687.                 back->r.statuscode=-1;
  688.               }    // sinon on est prΩts
  689.             } else {
  690.               strcpybuff(back->r.msg,"Unable to create a socket");
  691.               back->status=FTP_STATUS_READY;    // fini
  692.               back->r.statuscode=-1;
  693.             }    // sinon on est prΩts
  694.           } else {
  695.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  696.             back->status=FTP_STATUS_READY;    // fini
  697.             back->r.statuscode=-1;
  698.           }    // sinon on est prΩts
  699.         } else {
  700.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  701.           back->status=FTP_STATUS_READY;    // fini
  702.           back->r.statuscode=-1;
  703.         }    // sinon on est prΩts
  704. #else
  705.         //T_SOC soc_servdat;
  706.         strcpybuff(back->info,"listening");
  707.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  708.           _CHECK_HALT_FTP;      
  709.           send_line(soc_ctl,line);          // envoi du RETR
  710.           get_ftp_line(soc_ctl,line,timeout);
  711.           _CHECK_HALT_FTP;      
  712.           if (line[0]=='2') {  // ok
  713.             strcpybuff(back->info,"retr");
  714.             strcpybuff(line,line_retr);
  715.             send_line(soc_ctl,line);
  716.             get_ftp_line(soc_ctl,line,timeout);
  717.             _CHECK_HALT_FTP;      
  718.             if (line[0]=='1') {
  719.               //T_SOC soc_dat;
  720.               struct sockaddr dummyaddr;
  721.               int dummylen = sizeof(struct sockaddr);
  722.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  723.                 strcpybuff(back->r.msg,"Unable to accept connection");
  724.                 back->status=FTP_STATUS_READY;    // fini
  725.                 back->r.statuscode=-1;
  726.               }
  727.             } else {
  728.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  729.               back->status=FTP_STATUS_READY;    // fini
  730.               back->r.statuscode=-1;
  731.             }
  732.           } else {
  733.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  734.             back->status=FTP_STATUS_READY;    // fini
  735.             back->r.statuscode=-1;
  736.           }
  737. #if HTS_WIN
  738.           closesocket(soc_servdat);
  739. #else
  740.           close(soc_servdat);
  741. #endif
  742.         } else {
  743.           strcpybuff(back->r.msg,"Unable to listen to a port");
  744.           back->status=FTP_STATUS_READY;    // fini
  745.           back->r.statuscode=-1;
  746.         }
  747. #endif
  748.         
  749.         //
  750.         // Ok, connexion initiΘe
  751.         //
  752.         if (soc_dat != INVALID_SOCKET) {
  753.           if (rest_understood) {         // REST envoyΘe et comprise
  754.             filenote(back->url_sav,NULL);
  755.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  756.           } else
  757.             back->r.fp = filecreate(back->url_sav);
  758.           strcpybuff(back->info,"receiving");
  759.           if (back->r.fp != NULL) {
  760.             char buff[1024];
  761.             int len=1;
  762.             int read_len=1024;
  763.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  764.             
  765.             while( (len>0) && (!stop_ftp(back)) ) {
  766.               // attendre les donnΘes
  767.               len=1;    // pas d'erreur pour le moment
  768.               switch(wait_socket_receive(soc_dat,timeout)) {
  769.               case -1:
  770.                 strcpybuff(back->r.msg,"FTP read error");
  771.                 back->status=FTP_STATUS_READY;    // fini
  772.                 back->r.statuscode=-1;
  773.                 len=0;    // fin
  774.                 break;
  775.               case 0:
  776.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  777.                 back->status=FTP_STATUS_READY;    // fini
  778.                 back->r.statuscode=-1;
  779.                 len=0;    // fin
  780.                 break;
  781.               }
  782.               
  783.               // rΘception
  784.               if (len) {
  785.                 len=recv(soc_dat,buff,read_len,0);
  786.                 if (len>0) {
  787.                   back->r.size+=len;
  788.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  789.                   if (back->r.fp) {
  790.                     if ((INTsys)fwrite(buff,1,(INTsys)len,back->r.fp) != len) {
  791.                       /*
  792.                       int fcheck;
  793.                       if ((fcheck=check_fatal_io_errno())) {
  794.                         opt->state.exit_xh=-1;
  795.                       }
  796.                       */
  797.                       strcpybuff(back->r.msg,"Write error");
  798.                       back->status=FTP_STATUS_READY;    // fini
  799.                       back->r.statuscode=-1;
  800.                       len=0;  // error
  801.                     }
  802.                   } else {
  803.                     strcpybuff(back->r.msg,"Unexpected write error");
  804.                     back->status=FTP_STATUS_READY;    // fini
  805.                     back->r.statuscode=-1;
  806.                   }
  807.                 } else {        // Erreur ou terminΘ
  808.                   back->status=FTP_STATUS_READY;    // fini
  809.                   back->r.statuscode=0;
  810.                   if (back->r.totalsize > 0 && back->r.size != back->r.totalsize) {
  811.                     back->r.statuscode=-1;
  812.                     strcpybuff(back->r.msg,"FTP file incomplete");
  813.                   }
  814.                 }
  815.                 read_len=1024; 
  816.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  817.               }
  818.             }
  819.             if (back->r.fp) { 
  820.               fclose(back->r.fp); 
  821.               back->r.fp=NULL;
  822.             }
  823.           } else {
  824.             strcpybuff(back->r.msg,"Unable to write file");
  825.             back->status=FTP_STATUS_READY;    // fini
  826.             back->r.statuscode=-1;
  827.           }
  828. #if HTS_WIN
  829.           closesocket(soc_dat);
  830. #else
  831.           close(soc_dat);
  832. #endif
  833.           
  834.           // 226 Transfer complete?
  835.           if (back->r.statuscode != -1) {
  836.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  837.               // rΘcupΘrer 226 transfer complete
  838.               get_ftp_line(soc_ctl,line,timeout);
  839.               if (line[0]=='2') {       // OK
  840.                 strcpybuff(back->r.msg,"OK");
  841.                 back->status=FTP_STATUS_READY;    // fini
  842.                 back->r.statuscode=200;
  843.               } else {
  844.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  845.                 back->status=FTP_STATUS_READY;    // fini
  846.                 back->r.statuscode=-1;
  847.               }
  848.             } else {
  849.               strcpybuff(back->r.msg,"FTP read error");
  850.               back->status=FTP_STATUS_READY;    // fini
  851.               back->r.statuscode=-1;
  852.             }
  853.           }
  854.           
  855.         }
  856.         
  857.         
  858.         
  859.       }
  860.       
  861.       
  862.     }
  863.     
  864.     _CHECK_HALT_FTP;
  865.     strcpybuff(back->info,"quit");
  866.     send_line(soc_ctl,"QUIT");    // bye bye
  867.     get_ftp_line(soc_ctl,NULL,timeout);
  868. #if HTS_WIN
  869.     closesocket(soc_ctl);
  870. #else
  871.     close(soc_ctl);
  872. #endif
  873.   }
  874.   
  875.   if (back->r.statuscode!=-1) {
  876.     back->r.statuscode=200;
  877.     strcpybuff(back->r.msg,"OK");
  878.   }
  879.   back->status=FTP_STATUS_READY;    // fini
  880.   return 0;
  881. }
  882.  
  883.  
  884.  
  885. // ouverture d'un port
  886. T_SOC get_datasocket(char* to_send) {
  887.   T_SOC soc = INVALID_SOCKET;
  888.   char h_loc[256+2];
  889.   
  890.   to_send[0]='\0';
  891.   if (gethostname(h_loc,256)==0) {    // host name
  892.     SOCaddr server;
  893.     int server_size=sizeof(server);
  894.     t_hostent* hp_loc;
  895.     t_fullhostent buffer;
  896.  
  897.     // effacer structure
  898.     memset(&server, 0, sizeof(server));
  899.  
  900.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  901.  
  902.       // copie adresse
  903.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  904.  
  905.       if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  906.  
  907.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  908.           SOCaddr server2;
  909.           int len;
  910.           len=sizeof(server2);
  911.           // effacer structure
  912.           memset(&server2, 0, sizeof(server2));
  913.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  914.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  915.             if (listen(soc,10)>=0) {    // au pif le 10
  916. #if HTS_INET6==0
  917.               unsigned short int a,n1,n2;
  918.               // calculer port
  919.               a  = SOCaddr_sinport(server2);
  920.               n1 = (a & 0xff);
  921.               n2 = ((a>>8) & 0xff);
  922.               {
  923.                 char dots[256+2];
  924.                 char dot[256+2];
  925.                 char* a;
  926.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  927.                 //
  928.                 dots[0]='\0';
  929.                 strncatbuff(dots, dot, 128);
  930.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  931.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  932.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  933.               }
  934. #else
  935.               /*
  936.                 EPRT |1|132.235.1.2|6275|
  937.                 EPRT |2|1080::8:800:200C:417A|5282|
  938.               */
  939.               {
  940.                 char dot[256+2];
  941.                 SOCaddr_inetntoa(dot, 256, server2, len);
  942.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  943.               }
  944. #endif
  945.               
  946.             } else {
  947. #if HTS_WIN
  948.               closesocket(soc);
  949. #else
  950.               close(soc);
  951. #endif
  952.               soc=INVALID_SOCKET;
  953.             }
  954.             
  955.             
  956.           } else {
  957. #if HTS_WIN
  958.             closesocket(soc);
  959. #else
  960.             close(soc);
  961. #endif
  962.             soc=INVALID_SOCKET;
  963.           }
  964.           
  965.           
  966.         } else {
  967. #if HTS_WIN
  968.           closesocket(soc);
  969. #else
  970.           close(soc);
  971. #endif
  972.           soc=INVALID_SOCKET;
  973.         }
  974.       }
  975.     }
  976.   }
  977.   
  978.   
  979.   return soc;
  980. }
  981.  
  982. #if FTP_DEBUG
  983. FILE* dd=NULL;
  984. #endif
  985.  
  986. // routines de rΘception/Θmission
  987. // 0 = ERROR
  988. int send_line(T_SOC soc,char* data) {
  989.   char line[1024];
  990.   if (_DEBUG_HEAD) {
  991.     if (ioinfo) {
  992.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  993.       fflush(ioinfo);
  994.     }
  995.   }
  996. #if FTP_DEBUG
  997.   if (dd == NULL) dd = fopen("toto.txt","w");
  998.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  999.   printf("---> %s",data); fflush(stdout);
  1000. #endif
  1001.   sprintf(line,"%s\x0d\x0a",data);
  1002.   if (check_socket_connect(soc) != 1) {
  1003. #if FTP_DEBUG
  1004.     printf("!SOC WRITE ERROR\n");
  1005. #endif
  1006.     return 0;    // erreur, plus connectΘ!
  1007.   }
  1008. #if FTP_DEBUG
  1009.   {
  1010.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  1011.     printf("%s\x0d\x0a",data); fflush(stdout);
  1012.     return r;
  1013.   }
  1014. #else
  1015.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  1016. #endif
  1017. }
  1018.  
  1019. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  1020.   char data[1024];
  1021.   int i,ok,multiline;
  1022. #if FTP_DEBUG
  1023.   if (dd == NULL) dd = fopen("toto.txt","w");
  1024. #endif
  1025.   
  1026.   data[0]='\0';
  1027.   i=ok=multiline=0; data[3]='\0';
  1028.   do {
  1029.     char b;                        
  1030.     
  1031.     // vΘrifier donnΘes
  1032.     switch(wait_socket_receive(soc,timeout)) {
  1033.     case -1:   // erreur de lecture
  1034.       if (line) strcpybuff(line,"500 *read error");
  1035.       return 0;
  1036.       break;
  1037.     case 0:
  1038.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  1039.       return 0;
  1040.       break;
  1041.     }
  1042.     
  1043.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  1044.     switch(recv(soc,&b,1,0)) {
  1045.       //case 0: break;    // pas encore --> erreur (on attend)!
  1046.     case 1:
  1047.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  1048.       if ((b!=10) && (b!=13))
  1049.         data[i++]=b;
  1050.       break;
  1051.     default:
  1052.       if (line) strcpybuff(line,"500 *read error");
  1053.       return 0; // error
  1054.       break;
  1055.     }
  1056.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  1057.       if (
  1058.         (data[3] == '-')
  1059.         ||
  1060.         ((multiline) && (!isdigit((unsigned char)data[0]))) 
  1061.         )
  1062.       {
  1063.         data[3]='\0';
  1064.         i=0;
  1065.         multiline=1;
  1066.       }
  1067.       else
  1068.         ok=1;    // sortir
  1069.     }
  1070.   } while(!ok);
  1071.   data[i++]='\0';
  1072.   
  1073.   if (_DEBUG_HEAD) {
  1074.     if (ioinfo) {
  1075.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1076.       fflush(ioinfo);
  1077.     }
  1078.   }
  1079. #if FTP_DEBUG
  1080.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1081.   printf("<--- %s\n",data);
  1082. #endif
  1083.   if (line) strcpybuff(line,data);
  1084.   return (strnotempty(data));
  1085. }
  1086.  
  1087. // sauter NNN
  1088. char* linejmp(char* line) {
  1089.   if (strlen(line)>4)
  1090.     return line+4;
  1091.   else
  1092.     return line;
  1093. }
  1094.  
  1095. // test socket:
  1096. // 0 : no data
  1097. // 1 : data detected
  1098. // -1: error
  1099. int check_socket(T_SOC soc) {
  1100.   fd_set fds,fds_e;           // poll structures
  1101.   struct timeval tv;          // structure for select
  1102.   FD_ZERO(&fds);
  1103.   FD_ZERO(&fds_e); 
  1104.   // socket read 
  1105.   FD_SET(soc,&fds);           
  1106.   // socket error
  1107.   FD_SET(soc,&fds_e);
  1108.   tv.tv_sec=0;
  1109.   tv.tv_usec=0;
  1110.   // poll!     
  1111.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1112.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1113.     return -1;
  1114.   } else if (FD_ISSET(soc,&fds)) {
  1115.     return 1;
  1116.   }
  1117.   return 0;
  1118. }
  1119. // check if connected
  1120. int check_socket_connect(T_SOC soc) {
  1121.   fd_set fds,fds_e;           // poll structures
  1122.   struct timeval tv;          // structure for select
  1123.   FD_ZERO(&fds);
  1124.   FD_ZERO(&fds_e); 
  1125.   // socket write 
  1126.   FD_SET(soc,&fds);           
  1127.   // socket error
  1128.   FD_SET(soc,&fds_e);
  1129.   tv.tv_sec=0;
  1130.   tv.tv_usec=0;
  1131.   // poll!     
  1132.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1133.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1134.     return -1;
  1135.   } else if (FD_ISSET(soc,&fds)) {
  1136.     return 1;
  1137.   }
  1138.   return 0;
  1139. }
  1140. // attendre des donnΘes
  1141. int wait_socket_receive(T_SOC soc,int timeout) {
  1142.   // attendre les donnΘes
  1143.   TStamp ltime=time_local();
  1144.   int r;
  1145. #if FTP_DEBUG
  1146.   printf("\x0dWaiting for data "); fflush(stdout);
  1147. #endif
  1148.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1149.     Sleep(100);
  1150. #if FTP_DEBUG
  1151.     printf("."); fflush(stdout);
  1152. #endif
  1153.   }
  1154. #if FTP_DEBUG
  1155.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1156. #endif
  1157.   return r;
  1158. }
  1159.  
  1160.  
  1161. // cancel reτu?
  1162. int stop_ftp(lien_back* back) {
  1163.   if (back->stop_ftp) {
  1164.     strcpybuff(back->r.msg,"Cancelled by User");
  1165.     back->status=FTP_STATUS_READY;    // fini
  1166.     back->r.statuscode=-1;
  1167.     return 1;
  1168.   }
  1169.   return 0;
  1170. }
  1171.  
  1172.  
  1173.  
  1174.  
  1175.